{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "tags": [
     "remove-cell"
    ]
   },
   "outputs": [],
   "source": [
    "import sys\n",
    "import os\n",
    "if not any(path.endswith('textbook') for path in sys.path):\n",
    "    sys.path.append(os.path.abspath('../../..'))\n",
    "from textbook_utils import *\n",
    "\n",
    "csv_file = 'data/Full24hrdataset.csv'\n",
    "usecols = ['Date', 'ID', 'region', 'PM25FM', 'PM25cf1']\n",
    "full = (pd.read_csv(csv_file, usecols=usecols, parse_dates=['Date'])\n",
    "        .dropna())\n",
    "full.columns = ['date', 'id', 'region', 'pm25aqs', 'pm25pa']\n",
    "\n",
    "GA = full.loc[(full['id'] == 'GA1')  , :]"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(sec:linear_simple_fit)=\n",
    "# Fitting the Simple Linear Model"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We stated earlier in this chapter that when we minimize the average loss over the data:\n",
    "\n",
    "$$\n",
    "\\frac{1}{n} \\sum_{i}[y_i - (\\theta_0 + \\theta_1 x_i)]^2\n",
    "$$\n",
    "\n",
    "the best-fitting line has intercept and slope:\n",
    "\n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\hat{\\theta}_0 &= \\bar{y} - \\hat{\\theta}_1 \\bar{x} \\\\\n",
    "\\hat{\\theta}_1 &= r({\\mathbf{x}},{\\mathbf{y}}) \\frac{SD({\\mathbf{y}})}{SD({\\mathbf{x}})}\n",
    "\\end{aligned}\n",
    "$$\n",
    "\n",
    "In this section, we use calculus to derive these results."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With the simple linear model, the mean squared error is a function of two model parameters, the intercept and slope. This means that if we use calculus to find the minimizing parameter values, we need to find the partial derivatives of the MSE with respect to $\\theta_0$ and $\\theta_1$. We can also find these minimizing values through other techniques:\n",
    "\n",
    "*Gradient descent*\n",
    ": We can use numerical optimization techniques, such as gradient descent, when the loss function is more complex and it's faster to find an approximate solution that's pretty accurate (see {numref}`Chapter %s <ch:gd>`).\n",
    "\n",
    "*Quadratic formula*\n",
    ": Since the average loss is a quadratic function of $ \\theta_0$ and $ \\theta_1 $, we can use the quadratic formula (along with some algebra) to solve for the minimizing parameter values. \n",
    "\n",
    "*Geometric argument*\n",
    ": Later in this chapter, we use a geometric interpretation of least squares to fit multiple linear models. This approach relates to the Pythagorean theorem and has several intuitive benefits."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We choose calculus to optimize the simple linear model since it is quick and straightforward. To begin, we take the partial derivatives of the sum of squared errors with respect to each parameter (we can ignore the e$1/n$ in the MSE because it doesn't affect the location of the minimum):\n",
    " \n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\frac{\\partial}{\\partial \\theta_0} \\sum_{i}[y_i - (\\theta_0 + \\theta_1 x_i)]^2\n",
    "  &=  \\sum_{i} 2 (y_i - \\theta_0 - \\theta_1 x_i ) (-1)\\\\\n",
    " & \\\\ \n",
    "\\frac{\\partial}{\\partial \\theta_1} \\sum_{i}[y_i - (\\theta_0 + \\theta_1 x_i)]^2,\n",
    "  &= \\sum_{i} 2 (y_i - \\theta_0 - \\theta_1 x_i) (-x_i)  \n",
    "\\end{aligned}\n",
    "$$"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then we set the partial derivatives equal to 0 and simplify a bit by multiplying both sides of the equations by $-1/2$ to get:"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$\n",
    "\\begin{aligned}\n",
    " 0   &= \\sum_{i} (y_i - \\hat{\\theta}_0 - \\hat{\\theta}_1 x_i) \\\\\n",
    " 0   &= \\sum_{i} (y_i - \\hat{\\theta}_0 - \\hat{\\theta}_1 x_i)x_i \\\\\n",
    "\\end{aligned}\n",
    "$$"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These equations are called the *normal equations*. \n",
    "In the first equation, we see that $\\hat{\\theta}_0$ can be represented as a function of $\\hat{\\theta}_1$:\n",
    "\n",
    "$$\n",
    "\\hat{\\theta}_0 = \\bar{y} - \\hat{\\theta}_1 \\bar{x}\n",
    "$$\n",
    "\n",
    "Plugging this value into the second equation gives us:\n",
    "\n",
    "$$\n",
    "\\begin{aligned}\n",
    " 0   &= \\sum_{i} (y_i - \\bar y + \\hat{\\theta}_1 \\bar x - \\hat{\\theta}_1 x_i ) x_i \\\\\n",
    "  &= \\sum_{i} [(y_i - \\bar y) - \\hat{\\theta}_1 ( x_i - \\bar x)]x_i \\\\ \n",
    "\\hat{\\theta}_1  &= \\frac{\\sum_{i} (y_i - \\bar y)x_i} {\\sum_{i}( x_i - \\bar x)x_i} \\\\\n",
    "\\end{aligned}\n",
    "$$"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After some algebra, we can represent $\\hat{\\theta}_1$ in terms of quantities that we are familiar with:\n",
    "\n",
    "$$\n",
    "\\hat{\\theta}_1 = r({\\mathbf{x}},{\\mathbf{y}}) \\frac{SD({\\mathbf{y}})}{SD({\\mathbf{x}})}\n",
    "$$\n",
    "\n",
    "As shown earlier in this chapter, this representation says that a point on the fitted line at $x$ can be written as follows:\n",
    "\n",
    "$$ \n",
    "\\hat{\\theta}_0 + \\hat{\\theta}_1 x \n",
    "= \\bar{y} + r({\\mathbf{x}},{\\mathbf{y}}) SD({\\mathbf{y}}) \\frac{(x - \\bar{x})}{SD({\\mathbf{x}})} \n",
    "$$"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have derived the equation  for the least squares line that we used in the previous section. There, we used the `pandas` built-in methods to compute\n",
    "$SD(\\mathbf{x})$, $SD(\\mathbf{y})$, and $r(\\mathbf{x}, \\mathbf{y})$,\n",
    "to easily calculate the equation for this line.\n",
    "However, in practice we recommend using the functionality provided in `scikit-learn` to do the model fitting:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LinearRegression \n",
    "\n",
    "y = GA['pm25pa']\n",
    "x = GA[['pm25aqs']]\n",
    "reg = LinearRegression().fit(x, y)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our fitted model is:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: PA estimate = -3.36 + 2.10AQS\n"
     ]
    }
   ],
   "source": [
    "print(f\"Model: PA estimate = {reg.intercept_:.2f} + {reg.coef_[0]:.2f}AQS\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice that we provided `y` as an array and `x` as a data frame to `LinearRegression`. We will soon see why when we fit multiple explanatory features in a model. \n",
    "\n",
    "The `LinearRegression` method offers numerically stable algorithms to fit linear models by least squares. This is especially important when fitting multiple variables, which we introduce next."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
